package ratkit.parameter;

import java.util.StringTokenizer;

import ratkit.parameter.RatKitParameter.ParameterTypes;
import ratkit.parameter.RatKitParameter.Type;
import ratkit.util.RatKitConstants;


/**
 * This class express @RatKitTest Annotation parameters. Simulation testers can
 * use this @RatKitTest to define inner parameters with the annotation. Each
 * parameter defined in the header of the test method expressed as an simulation
 * environment parameter and used globally in the simulation.
 * 
 * @author İbrahim Çakırlar
 * @version 1.0
 * 
 */
public class TestParameter implements Cloneable {

	/**
	 * Name of the test parameter.
	 */
	private String parameterName;
	/**
	 * Value of the test parameter.
	 */
	private String parameterValue;
	/**
	 * Type of the test parameter.
	 */
	private String parameterType;

	/**
	 * Initial value for the parameter value iteration.
	 */
	private String from;

	/**
	 * Last value for the parameter value iteration.
	 */
	private String to;

	/**
	 * Increment value for the parameter value iteration.
	 */
	private String step;

	/**
	 * Parameter sweeping type for the test parameter.
	 */
	private Type type;

	/**
	 * Sets the test parameter name.
	 */
	public void setParameterName(String parameterName) {
		this.parameterName = parameterName;
	}

	/**
	 * @return name of the parameter.
	 */
	public String getParameterName() {
		return parameterName;
	}

	public void setParameterValue(String parameterValue) {
		this.parameterValue = parameterValue;
	}

	public String getParameterValue() {
		return parameterValue;
	}

	public void setParameterType(String parameterType) {
		this.parameterType = parameterType;
	}

	public String getParameterType() {
		return parameterType;
	}

	public void setFrom(String from) {
		this.from = from;
	}

	public String getFrom() {
		return from;
	}

	public void setTo(String to) {
		this.to = to;
	}

	public String getTo() {
		return to;
	}

	public void setStep(String step) {
		this.step = step;
	}

	public String getStep() {
		return step;
	}

	public void setType(Type type) {
		this.type = type;
	}

	public Type getType() {
		return type;
	}

	/**
	 * Creates a new {@code TestParameter} clone of the current parameter
	 * instance for parameter sweeping.
	 */
	@Override
	protected Object clone() throws CloneNotSupportedException {
		TestParameter clone = (TestParameter) super.clone();
		clone.setParameterName(this.getParameterName());
		clone.setFrom(this.getFrom());
		clone.setParameterType(this.getParameterType());
		clone.setParameterValue(this.getParameterValue());
		clone.setStep(this.getStep());
		clone.setTo(this.getTo());
		clone.setType(this.getType());
		return clone;
	}

	/**
	 * Calculates the sweep run count. Calculation is fulfilled according to
	 * from, to and step values in {@code Type#NUMBER} parameters otherwise the
	 * parameter value is used in {@code Type#LIST}. If the
	 * {@code Type#CONSTANT} sweep run count is always equal to 1.
	 * 
	 * @return sweep run for the test parameter..
	 */
	public int getSweepRun() {
		// calculate sweep run count according to the parameter type..
		if (this.type == Type.NUMBER) {
			// cast to,from and step values according to the parameterType
			// value.
			if (this.parameterType.equals(ParameterTypes.INT)) {
				int from = Integer.valueOf(getFrom());
				int to = Integer.valueOf(getTo());
				int step = Integer.valueOf(getStep());
				return (((to) - from) / step) + 1;
			} else if (this.parameterType.equals(ParameterTypes.DOUBLE)) {
				double from = Double.valueOf(getFrom());
				double to = Double.valueOf(getTo());
				double step = Double.valueOf(getStep());
				return (int) ((((to) - from) / step) + 1);
			} else if (this.parameterType.equals(ParameterTypes.SHORT)) {
				short from = Short.valueOf(getFrom());
				short to = Short.valueOf(getTo());
				short step = Short.valueOf(getStep());
				return (int) ((((to) - from) / step) + 1);
			} else if (this.parameterType.equals(ParameterTypes.FLOAT)) {
				float from = Float.valueOf(getFrom());
				float to = Float.valueOf(getTo());
				float step = Float.valueOf(getStep());
				return (int) ((((to) - from) / step) + 1);
			} else if (this.parameterType.equals(ParameterTypes.LONG)) {
				long from = Long.valueOf(getFrom());
				long to = Long.valueOf(getTo());
				long step = Long.valueOf(getStep());
				return (int) ((((to) - from) / step) + 1);
			}
			// process list type test parameters.
		} else if (this.type == Type.LIST) {
			StringTokenizer tokenizer = new StringTokenizer(
					getParameterValue(), RatKitConstants.COMMA);
			if (tokenizer.countTokens() == 0) {
				tokenizer = new StringTokenizer(getParameterValue());
			}
			return tokenizer.countTokens();
		}
		return 1;
	}

	/**
	 * Returns the sweep run parameter value for the sweeping parameters. If the
	 * type of the test parameter is {@code Type#NUMBER} it calculates the given
	 * sweep run index value and return the parameter value according to the
	 * from, to and step values. And If the type of the test parameter is
	 * {@code Type#LIST} it splits the given list value and returns the index
	 * element of the value list. Otherwise return the value of the parameter.
	 * 
	 * @param sweepRunIndex
	 *            index of the sweep run.
	 * @return parameter value.
	 */
	public String getNextValue(int sweepRunIndex) {
		// get number type values according to the parameterValue.
		if (this.type == Type.NUMBER) {
			if (this.parameterType.equals(ParameterTypes.INT)) {
				int from = Integer.valueOf(getFrom());
				int step = Integer.valueOf(getStep());
				return "" + (from + (step) * sweepRunIndex);
			} else if (this.parameterType.equals(ParameterTypes.DOUBLE)) {
				double from = Double.valueOf(getFrom());
				double step = Double.valueOf(getStep());
				return "" + (from + (step * sweepRunIndex));
			} else if (this.parameterType.equals(ParameterTypes.SHORT)) {
				short from = Short.valueOf(getFrom());
				short step = Short.valueOf(getStep());
				return "" + (from + (step * sweepRunIndex));
			} else if (this.parameterType.equals(ParameterTypes.FLOAT)) {
				float from = Float.valueOf(getFrom());
				float step = Float.valueOf(getStep());
				return "" + (from + (step * sweepRunIndex));
			} else if (this.parameterType.equals(ParameterTypes.LONG)) {
				long from = Long.valueOf(getFrom());
				long step = Long.valueOf(getStep());
				return "" + (from + (step * sweepRunIndex));
			}
		}// get the sweep run value of the LIST type parameters.
		if (this.type == Type.LIST) {
			// parse the given list.
			// list can be comma separated or space separated.
			StringTokenizer tokenizer = new StringTokenizer(
					getParameterValue(), RatKitConstants.COMMA);
			if (tokenizer.countTokens() == 1) {
				tokenizer = new StringTokenizer(getParameterValue());
			}
			// get values to an temporary list.
			String[] values = new String[tokenizer.countTokens()];
			int i = 0;
			while (tokenizer.hasMoreTokens()) {
				values[i] = tokenizer.nextToken();
				i++;
			}
			return values[sweepRunIndex];
		}
		// otherwise return the parameter value
		return parameterValue;
	}

}
